package modelo.policiales;

import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import modelo.delictivas.Robo;
import modelo.delictivas.TesoroNacional;
import modelo.geografia.Capital;
import modelo.geografia.Viaje;


public class Investigacion {

	private int tiempoDisponible;
	private List<Viaje> listaViajes;
	private Robo robo;
	private OrdenArresto ordenArresto;
	private DatosLadron datosLadron;

	private boolean enProceso;
	private boolean ladronArrestado;
	private int tiempoTotal;

	public Investigacion(int tiempoDisponible, Robo robo) {
		this.tiempoTotal = tiempoDisponible;
		this.tiempoDisponible = tiempoDisponible;
		this.listaViajes = new ArrayList<Viaje>();
		this.robo = robo;
		this.ordenArresto = null;
		this.enProceso = true;
		this.ladronArrestado = false;
		this.datosLadron = new DatosLadron();
	}

	public Investigacion(int tiempoTotal, int tiempoDisponible, Robo robo) {
		this.tiempoTotal = tiempoTotal;
		this.tiempoDisponible = tiempoDisponible;
		this.listaViajes = new ArrayList<Viaje>();
		this.robo = robo;
		this.ordenArresto = null;
		this.enProceso = true;
		this.ladronArrestado = false;
		this.datosLadron = new DatosLadron();
		
	}

	public void agregarViaje(Viaje unViaje) throws Exception {
				
		if( this.viajeEsValido(unViaje) ){
			this.listaViajes.add(unViaje);
		}
		else throw new Exception ("El viaje no es valido") ;
	}

	private boolean viajeEsValido(Viaje unViaje) {
		//Valida si la ultima capital en la que estuvo
		//es la capital de origen del nuevo viaje,
		//y para eso tambien necesita ver si la lista de viajes
		//no se encuentra vacia
		
		if ( this.listaViajes.size() != 0 ){
			
			Viaje ultimoViaje = this.listaViajes.get( this.listaViajes.size() -1 );
		
			Capital nuevoOrigen = ultimoViaje.getCapitalDestino();
			Capital nuevoDestino = unViaje.getCapitalOrigen();
		
			if (nuevoOrigen.obtenerDistanciaACapital(nuevoDestino) != 0)
				return false;
			}
		return true;
	}

	public int getTiempoDisponible() {
		return this.tiempoDisponible;
	}

	public boolean viajeADestinoEsRepetido(Capital capital) {
		
		boolean esRepetido = false;
		
		Iterator<Viaje> it = this.listaViajes.iterator();
		while(it.hasNext())
		{
			if(it.next().getCapitalDestino().equals(capital))
				esRepetido = true;
		}
		
		return esRepetido;
	}

	public int getCantidadDeViajes() {
		return this.listaViajes.size();
	}
	
	public TesoroNacional getTesoroRobado(){
		
		return this.robo.getTesoroRobado();		
	}

	public void reducirTiempo(int tiempoPerdido) {
		
		this.tiempoDisponible -= tiempoPerdido;	
	}

	public boolean tieneOrdenDeArresto() {
		return (this.ordenArresto != null);
	}

	public void setOrdenArresto(OrdenArresto ordenArresto) {
		
		this.ordenArresto = ordenArresto;
		
	}

	public void cerrar() {
		this.enProceso = false;
	}

	public boolean enProceso() {
		return this.enProceso;
	}

	public boolean ladronFueArrestado() {
		return this.ladronArrestado;
	}

	public Robo getRobo() {
		return this.robo;
		
	}

	public boolean ordenDeArrestoCorrespondeALadron(){
		if(!this.tieneOrdenDeArresto())
			return false;
		return this.robo.sospechosoEsCulpable(this.ordenArresto.getLadronBuscado());
	}

	public boolean puedeRealizarseArresto() {
		 return this.ordenDeArrestoCorrespondeALadron();
			 
	}

	public void asentarArrestoDeLadron() {
		this.ladronArrestado = true;
	}
	
	public OrdenArresto verOrdenDeArrestoDeLaInvestigacion(){
		
		return this.ordenArresto;
	}
	
	public DatosLadron getDatosLadron() {
		return this.datosLadron;
	}
	
	public Element serializar(Document doc) {
		
		Element elementoInvestigacion = doc.createElement("Investigacion");
		elementoInvestigacion.setAttribute("TiempoTotal", Integer.toString(this.tiempoTotal));
		elementoInvestigacion.setAttribute("TiempoDisponible", Integer.toString(this.tiempoDisponible));
		
		elementoInvestigacion.appendChild( this.robo.serializar(doc) );
		
		if (this.ordenArresto != null)
			elementoInvestigacion.appendChild(this.ordenArresto.serializar(doc));
		else{
			elementoInvestigacion.setAttribute("OrdenDeArresto", "No tiene");
			}
		
		elementoInvestigacion.setAttribute("EnProceso", Boolean.toString(this.enProceso) );
		elementoInvestigacion.setAttribute("LadronArrestado", Boolean.toString(this.ladronArrestado) );
		
		
		Element elementoDatosLadron = doc.createElement("datosLadron");
		
		if (this.datosLadron.getSexo() != null){
			elementoDatosLadron.setAttribute("sexo", this.datosLadron.getSexo().name());
		}
		else {
			elementoDatosLadron.setAttribute("sexo", "vacio");
		}
		if (this.datosLadron.getCabello() != null){
			elementoDatosLadron.setAttribute("cabello", this.datosLadron.getCabello().name());
		}
		else {
			elementoDatosLadron.setAttribute("cabello", "vacio");
		}
		if (this.datosLadron.getHobby() != null){
			elementoDatosLadron.setAttribute("hobby", this.datosLadron.getHobby().name());
		}
		else {
			elementoDatosLadron.setAttribute("hobby", "vacio");
		}
		if (this.datosLadron.getSenia() != null){
			elementoDatosLadron.setAttribute("senia", this.datosLadron.getSenia().name());
		}
		else {
			elementoDatosLadron.setAttribute("senia", "vacio");
		}
		if (this.datosLadron.getVehiculo() != null){
			elementoDatosLadron.setAttribute("vehiculo", this.datosLadron.getVehiculo().name());
		}
		else {
			elementoDatosLadron.setAttribute("vehiculo", "vacio");
		}
		elementoInvestigacion.appendChild(elementoDatosLadron);
		
		
		
		return elementoInvestigacion;
	}
	
	public static Investigacion hidratar(Element elementoInvestigacion) throws Exception {
		
		int tiempoTotal = Integer.parseInt( elementoInvestigacion.getAttribute("TiempoTotal") );

		int tiempoDisponible = Integer.parseInt( elementoInvestigacion.getAttribute("TiempoDisponible") );
		
		Robo robo = Robo.hidratar(elementoInvestigacion);
		
		Investigacion nuevaInvest = new Investigacion (tiempoTotal, tiempoDisponible,robo);
		
		if (! elementoInvestigacion.getAttribute("OrdenDeArresto").equals("No tiene")){
			OrdenArresto orden = OrdenArresto.hidratar((Element) elementoInvestigacion.getElementsByTagName("OrdenDeArresto").item(0));
			nuevaInvest.setOrdenArresto(orden);
		}
		
		String proceso = elementoInvestigacion.getAttribute("EnProceso");
		
		if (proceso.equals("false"))
			nuevaInvest.cerrar();
		
		String ladronArrestado = elementoInvestigacion.getAttribute("LadronArrestado");
		
		if (ladronArrestado.equals("true"))
			nuevaInvest.asentarArrestoDeLadron();
		
		nuevaInvest.setDatosLadron(DatosLadron.hidratar(elementoInvestigacion.getElementsByTagName("datosLadron").item(0)));
		
		return nuevaInvest;
	}
	
	private void setDatosLadron (DatosLadron datos){
		this.datosLadron = datos;
	}

	public int getTiempoTotal() {
		return this.tiempoTotal;
	}

	public void guardar(String nombrePolicia) throws ParserConfigurationException, TransformerException {
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = dbf.newDocumentBuilder();
		Document doc = db.newDocument();
		Element investigacionSerializada = this.serializar(doc);
		
		doc.appendChild(investigacionSerializada);
		TransformerFactory transformerFactory = TransformerFactory.newInstance();
		Transformer transformer = transformerFactory.newTransformer();
		DOMSource source = new DOMSource(doc);
		File archivoDestino = new File("Investigacion"+ nombrePolicia +".xml");
		StreamResult result = new StreamResult(archivoDestino);
		transformer.transform(source, result);
	}

	public OrdenArresto getOrdenArresto() {
		return this.ordenArresto;
	}
	
	
}
